/*
 * irq.c
 *
 *  Created on: 01/09/2010
 *      Author: Wendell
 *
 *  === IRS's ===
 *
 *  	Rotinas para Serviço de Interrupção, ou ISRs, são usados para salvar o
 * estado do processo corrente e atribuir os registradores de segmento
 * apropriadamente necessários para o modo kernel antes que o nível-C de
 * tratamento de interrupções do kernel é chamado. Isso é totalmente tratado em
 * aproximadamente 15 ou 20 linhas de linguagem assembly, incluindo o chamado do
 * nosso tratamento em C.
 * 		Nós precisaremos também apontar a entrada correta no IDT para o correto
 * ISR para tratar direito as exceções.
 *
 * 		Uma Exceção é um caso especial que o processador encontra quando este
 * pode não continuar a execução normal. Este pode ser somente uma divisão pode
 * zero: O resultado é um número desconhecido ou não-real, assim o processador
 * causará um exceção de modo que o kernel pode parar o processo ou tarefa de
 * causar quaisquer problemas.
 * 		Se o processador achar que um programa está tentando acessar um pedaço
 * da memória que este não pode, este irá causar uma Falta de Proteção Geral
 * (General Protection Fault).
 * 		Quando você atribuir paginação, o processador irá causar uma Falta de
 * Página (Page Fault), mas este é recuperável: você pode mapear um página na
 * memória para o endereço faltando. MAs esse é um passo mais avançado
 * 		As primeiras 32 entradas na IDT correspondem para Exceções que podem ser
 * gerados pelo processador, e portanto precisam ser tratados.
 * 		Algumas exceções vão puxar outros valores na pilha: um valor de Código
 * de Erro (Error Code) que é especifico para à exceção causada.
 *
 * Exceção #	 Descrição (Inglês)	 			Descrição (Português)	 			Código de Erro?
 * 0	Division By Zero Exception			Exceção de Divisão por Zero					Não
 * 1	Debug Exception						Exceção de Debug							Não
 * 2	Non Maskable Interrupt Exception	Exceção de Interrupção Não Mascarada		Não
 * 3	Breakpoint Exception				Exceção de Ponto de Parada (Breakpoint) 	Não
 * 4	Into Detected Overflow Exception	Exceção Overflow Interno Detectado			Não
 * 5	Out of Bounds Exception				Exceção de Fora dos Limites					Não
 * 6	Invalid Opcode Exception			Exceção de Opcode Invalido					Não
 * 7	No Coprocessor Exception			Exceção de Nenhum Coprocessador				Não
 * 8	Double Fault Exception				Exceção de Falta Dupla						Sim
 * 9	Coprocessor Segment Overrun Exception	Exceção de Coprocessador Segmento Overrun	Não
 * 10	Bad TSS Exception					Exceção de TSS Ruim							Sim
 * 11	Segment Not Present Exception		Exceção de Segmento Não Presente			Sim
 * 12	Stack Fault Exception				Exceção de Falha de Pilha					Sim
 * 13	General Protection Fault 			Exceção de Falha de Proteção Geral  		Sim
 * 14	Page Fault Exception				Exceção Falha de Página						Sim
 * 15	Unknown Interrupt Exception			Exceção de Interrupção Desconhecida			Não
 * 16	Coprocessor Fault Exception			Exceção de Falha Coprocessador				Não
 * 17	Alignment Check Exception (486+)	Exceção de Checagem de Alinhamento (486+)	Não
 * 18	Machine Check Exception (Pentium/586+)	Exceção de Checagem de Máquina (Pentium/586+)	Não
 * ...
 * 19 até 31	Reserved Exceptions			Exceções Reservado	Não
 *
 * 		Como mencionado anteriormente, algumas exceções puxam um código de erro para
 * a pilha. Para diminuir a complexidade, nós trataremos este  puxando uma copia
 * do código de erro de 0 na pilha para qualquer ISR não puxar um código de erro
 * já. Este guarda uma moldura de pilha uniforme.
 * 		Para trilhar qual exceção está disparando, nós também puxamos o número
 * da interrupção na pilha. Nós usamos o opcode assembly 'cli' para desabilitar
 * as interrupções e prevenir uma IRQ de disparar, que poderia de outro modo
 * causar conflitos em nosso kernel.
 * 		Para salvar espaço no kernel e fazer um pequeno arquivo de saída binário,
 * nós faremos cada ponta ISR pular para uma comum 'isr_common_stub'.
 * 		O 'isr_common_stub' vai salvar o estado do processo na pilha, puxar o
 * endereço da pilha corrente na pilha (do nosso tratamento C a pilha), chama
 * nossa função C 'fault_handler', e finalmente restaura o estado da pilha.
 *
 */
#include <system.h>
#include <graphic.h>

/**
 * Aqui estão todos os protótipos de função de todas os tratamentos de
*  exceções (exception handlers).
 * As primeiras 32 entradas do IDT são reservadas pela Intel, e elas são
 * projetadas para interrupções de serviços
 */
extern void isr0();
extern void isr1();
extern void isr2();
extern void isr3();
extern void isr4();
extern void isr5();
extern void isr6();
extern void isr7();
extern void isr8();
extern void isr9();
extern void isr10();
extern void isr11();
extern void isr12();
extern void isr13();
extern void isr14();
extern void isr15();
extern void isr16();
extern void isr17();
extern void isr18();
extern void isr19();
extern void isr20();
extern void isr21();
extern void isr22();
extern void isr23();
extern void isr24();
extern void isr25();
extern void isr26();
extern void isr27();
extern void isr28();
extern void isr29();
extern void isr30();
extern void isr31();

/**
 * Está é uma função muito repetitiva... não é difícil, é apenas chata!
 * Como você pode ver, nós atribuímos as 32 entradas
*  na IDT para as primeiras 32 ISRs. Nós não podemos usar um laço for
*  para isso, porque não há caminho de se obter os nomes das funções
*  que correspondem para cada entrada. Nós atribuímos as flags de
*  entrada para 0x8E. Fazer que a entrada esteja presente, está
*  rodando em ring 0 (nível kernel), e que os 5 bits inferiores
*  estejam atribuídos para o requerido '14', que é representado por 'E'
*  em hexadecimal.
 */
void isrsInstall() {
    idtSetGate(0, (unsigned)isr0, 0x08, 0x8E);
    idtSetGate(1, (unsigned)isr1, 0x08, 0x8E);
    idtSetGate(2, (unsigned)isr2, 0x08, 0x8E);
    idtSetGate(3, (unsigned)isr3, 0x08, 0x8E);
    idtSetGate(4, (unsigned)isr4, 0x08, 0x8E);
    idtSetGate(5, (unsigned)isr5, 0x08, 0x8E);
    idtSetGate(6, (unsigned)isr6, 0x08, 0x8E);
    idtSetGate(7, (unsigned)isr7, 0x08, 0x8E);

    idtSetGate(8, (unsigned)isr8, 0x08, 0x8E);
    idtSetGate(9, (unsigned)isr9, 0x08, 0x8E);
    idtSetGate(10, (unsigned)isr10, 0x08, 0x8E);
    idtSetGate(11, (unsigned)isr11, 0x08, 0x8E);
    idtSetGate(12, (unsigned)isr12, 0x08, 0x8E);
    idtSetGate(13, (unsigned)isr13, 0x08, 0x8E);
    idtSetGate(14, (unsigned)isr14, 0x08, 0x8E);
    idtSetGate(15, (unsigned)isr15, 0x08, 0x8E);

    idtSetGate(16, (unsigned)isr16, 0x08, 0x8E);
    idtSetGate(17, (unsigned)isr17, 0x08, 0x8E);
    idtSetGate(18, (unsigned)isr18, 0x08, 0x8E);
    idtSetGate(19, (unsigned)isr19, 0x08, 0x8E);
    idtSetGate(20, (unsigned)isr20, 0x08, 0x8E);
    idtSetGate(21, (unsigned)isr21, 0x08, 0x8E);
    idtSetGate(22, (unsigned)isr22, 0x08, 0x8E);
    idtSetGate(23, (unsigned)isr23, 0x08, 0x8E);

    idtSetGate(24, (unsigned)isr24, 0x08, 0x8E);
    idtSetGate(25, (unsigned)isr25, 0x08, 0x8E);
    idtSetGate(26, (unsigned)isr26, 0x08, 0x8E);
    idtSetGate(27, (unsigned)isr27, 0x08, 0x8E);
    idtSetGate(28, (unsigned)isr28, 0x08, 0x8E);
    idtSetGate(29, (unsigned)isr29, 0x08, 0x8E);
    idtSetGate(30, (unsigned)isr30, 0x08, 0x8E);
    idtSetGate(31, (unsigned)isr31, 0x08, 0x8E);
}

/* Este é um simples arranjo de string. Que contêm as mensagens que
*  correspondem para cada e toda exceção. Nós obtemos a mensagem
*  correta acessando por:
*  exception_message[interrupt_number] */
/**
 * Este é um simples array de strings que contêm as mensagens que
 * correspondem para cada exceção.
 * Nós obtemos a mensagem correta acessando por:
 * exception_message[interrupt_number]
 */
char *exception_messages[] = {
    "Divisao por Zero",
    "Debug",
    "Interrupcao Nao Mascarada",
    "Ponto de Parada (Breakpoint)",
    "Overflow Interno Detectado",
    "Fora dos Limites",
    "Opcode Invalido",
    "Nenhum Coprocessador",

    "Falha Dupla",
    "Coprocessor Segment Overrun",
    "TSS Ruim",
    "Segmento nao Presente",
    "Falha de Pilha",
    "Falha de Protecao Geral",
    "Falha de Pagina",
    "Interrupção Desconhecida",

    "Falha Coprocessador",
    "Checagem de Alinhamento",
    "Checagem de Maquina",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",

    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved",
    "Reserved"
};

/**
 * 		O nosso Exception handling Interrupt Service Routines aponta para
 * essa funcao. Ela nos avisa qual excecao ocorreu! Agora, nos simplesmente
 * paralisamos (halt) o sistema, iniciando um loop infinito.
 * 		All ISRs disable interrupts while they are being
*  serviced as a 'locking' mechanism to prevent an IRQ from
*  happening and messing up kernel data structures
 */
void fault_handler(struct regs *r) {
    if (r->int_no < 32) {
        print(exception_messages[r->int_no]);
        print(" Exception. System Halted!\n");
        for (;;);
    }
}
